package com.xuzimian.alibaba.coding.guideline;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * Producer Extends Consumer Super :
 * 如果参数化类型表示一个生产者，就使用<? extends T>；如果它表示一个消费者，就使用<? super T>
 * 参考链接：https://www.jianshu.com/p/e5b8cd33ec94
 */
public class ProducerExtendsConsumerSuperDemo {

    /**
     * 简单的说，当只想从集合中获取元素，请把这个集合看成生产者，请使用<? extends T>，
     * 这就是Producer extends原则，PECS原则中的PE部分。
     */
    @Test
    void testExtend() {
        List<Apple> apples = new ArrayList<>();
        apples.add(new Apple());

        /*
         泛型是不可变Fruit和Apple虽是父子关系，但作为2个不同的类型， List<Apple>和List<Fruit>之间没有继承关系，所以2者之间无法转化
         */
        // List<Fruit> fruits = apples;    //  编译不过:

        // List<? extends Fruit> 是 List<Fruit>和List<Apple>的超类型
        List<? extends Fruit> fruits = apples; //  编译通过。

        // 编译不过: List<Apple>和List<Fruit>，是2个完全没有关系的类型
        // 编译器不知道是哪个子类型将加入集合，不知道到底是 List<Apple>还是List<Fruit>
        // fruits.add(new Apple());

        // 编译器已经知道集合里全部都是水果的子类型，所以编译器可以保证取出的数据全部是水果。
        Fruit apple = fruits.get(0);
    }

    /**
     * 如果你只需要将类型T放到集合中, 使用<? super T>通配符
     */
    @Test
    void testSuper() {
        List<Apple> apples = new ArrayList<>();
        apples.add(new Apple());
        List<? super Apple> fruits = apples;

        // <? super Apple>相当于告诉编译器，集合接受处理Apple以及Apple的超类型，即Object，Fruit，Apple三个类型
        fruits.add(new Apple());
        fruits.add(new RedApple());
        //由于编译器并不知道List的内容究竟是Apple的哪个超类，因此不允许加入特定的任何超类型。
        // fruits.add(new Fruit()); //编译错误

        /*
        编译器不知道是按哪个类型取出， 到底是Object，Fruit，Apple中的哪个呢？但是编译器可以选择永远不会错的类型，
        也就是Object的类型，因为Object是所有类型的超类型。
         */
        Object object = fruits.get(0);  //正确
        // Fruit fruit =fruits.get(0);  //编译错误
        // Apple apple = fruits.get(0); //编译错误
        // RedApple redApple = fruits.get(0);  //编译错误
    }

    class Fruit {
    }

    class Apple extends Fruit {
    }

    class RedApple extends Apple {
    }

    class Pear extends Fruit {
    }


}
